﻿#ifndef MELSEC_3E_BINARY_H
#define MELSEC_3E_BINARY_H

#include <QTcpSocket>
#include <QByteArray>
#include <QBitArray>
#include <QVector>

class Melsec_Comm_3E_BINARY
{
public:
    int CPUtype(QTcpSocket * socket, uint32_t timeout, QString &cpu_string, uint16_t &cpu_code);
    int run(QTcpSocket * socket, uint32_t timeout, int mode, int clear_mode);
    int stop(QTcpSocket * socket, uint32_t timeout, int mode);
    int reset(QTcpSocket * socket, uint32_t timeout, int mode);
    int pause(QTcpSocket * socket, uint32_t timeout, int mode);
    int loopback(QTcpSocket * socket, uint32_t timeout, const QByteArray &in_data, QByteArray &out_data);// 折返测试

    QBitArray readBits(QTcpSocket * socket, uint32_t timeout, uint8_t code, uint32_t addr, uint16_t N);
    QByteArray readBytes(QTcpSocket * socket, uint32_t timeout, uint8_t code, uint32_t addr, uint16_t N);
    QVector<int16_t> readInt16(QTcpSocket * socket, uint32_t timeout, uint8_t code, uint32_t addr, uint16_t N);
    QVector<int32_t> readInt32(QTcpSocket * socket, uint32_t timeout, uint8_t code, uint32_t addr, uint16_t N);
    QVector<int64_t> readInt64(QTcpSocket * socket, uint32_t timeout, uint8_t code, uint32_t addr, uint16_t N);
    QVector<float> readFloat(QTcpSocket * socket, uint32_t timeout, uint8_t code, uint32_t addr, uint16_t N);
    QVector<double> readDouble(QTcpSocket * socket, uint32_t timeout, uint8_t code, uint32_t addr, uint16_t N);
    QByteArray readString(QTcpSocket * socket, uint32_t timeout, uint8_t code, uint32_t addr, uint16_t N);

    uint16_t writeBits(QTcpSocket * socket, uint32_t timeout, uint8_t code, uint32_t addr, QBitArray array);
    uint16_t writeBytes(QTcpSocket * socket, uint32_t timeout, uint8_t code, uint32_t addr, QVector<uint16_t> array);
private:
    QByteArray read(QTcpSocket *socket, int length);
    int write(QTcpSocket *socket, QByteArray data);
};


enum SoftCode
{
    X = 0x9C,
    Y = 0x9D,
    M = 0x90,
    L = 0x92,
    S = 0x98,
    B = 0xA0,
    F = 0x93,
    TS = 0xC1,
    TC = 0xC0,
    TN = 0xC2,
    CS = 0xC4,
    CC = 0xC3,
    CN = 0xC5,
    D = 0xA8,
    W = 0xB4,
    R = 0xAF,
    ZR = 0xB0
};
class CommandFrame_MC_3E_BINARY
{
protected:
    QByteArray buildFrame(QByteArray cmd_text);
    QByteArray textLength(QByteArray text);
    QByteArray address(uint32_t addr);
    QByteArray uint8ToHex(uint8_t x);
    QByteArray uint16ToHex(uint16_t x);
    QByteArray uint24ToHex(uint32_t x);
    QByteArray uint32ToHex(uint32_t x);
    QByteArray uint48ToHex(uint64_t x);
    QByteArray uint64ToHex(uint64_t x);
};

/**
 * @brief The CommandFrame_1001_BINARY class 远程 RUN 命令
 */
class CommandFrame_1001_BINARY : public CommandFrame_MC_3E_BINARY
{
public:
    QByteArray build(int mode, int clear_mode);
};

/**
 * @brief The CommandFrame_1002_BINARY class 远程 STOP 命令
 */
class CommandFrame_1002_BINARY : public CommandFrame_MC_3E_BINARY
{
public:
    QByteArray build(int mode);
};

/**
 * @brief The CommandFrame_1005_BINARY class 远程锁存清除 命令
 */
class CommandFrame_1005_BINARY : public CommandFrame_MC_3E_BINARY
{
public:
    QByteArray build(int mode);
};

/**
 * @brief The CommandFrame_0101_BINARY class CPU 型号读出 命令
 */
class CommandFrame_0101_BINARY : public CommandFrame_MC_3E_BINARY
{
public:
    QByteArray build();
};

/**
 * @brief The CommandFrame_1006_BINARY class 远程 RESET 命令
 */
class CommandFrame_1006_BINARY : public CommandFrame_MC_3E_BINARY
{
public:
    QByteArray build(int mode);
};

/**
 * @brief The CommandFrame_1003_BINARY class 远程 PAUSE 命令
 */
class CommandFrame_1003_BINARY : public CommandFrame_MC_3E_BINARY
{
public:
    QByteArray build(int mode);
};

class CommandFrame_0619_BINARY : public CommandFrame_MC_3E_BINARY
{
public:
    QByteArray build(QByteArray t);
};

/**
 * @brief The CommandFrame_1401_BINARY class 成批写入命令
 *  用于将数据写入指定个数的连续软元件中。
 */
class CommandFrame_1401_BINARY : public CommandFrame_MC_3E_BINARY
{
public:
    /**
     * @brief build 以位为单位写入软元件。对应子命令 0001
     * @param code 指定软元件类型，比如 "M*", "D*"
     * @param addr 软元件的起始地址
     * @param array 数据
     * @return
     */
    QByteArray build(uint8_t code, uint32_t addr, QBitArray array);

    /**
     * @brief build 以字为单位写入软元件。对应子命令 0000
     * @param code 指定软元件类型，比如 "M*", "D*"
     * @param addr 软元件的起始地址
     * @param array 数据，每个uint16_t 对应 16 个线圈
     * @return
     */
    QByteArray build(uint8_t code, uint32_t addr, QVector<uint16_t> array);
private:
    QByteArray bitToArray(QBitArray array);
};


class CommandFrame_0401_BINARY : public CommandFrame_MC_3E_BINARY
{
public:
    QByteArray readBits(uint8_t code, uint32_t addr, uint16_t N);
    QByteArray readBytes(uint8_t code, uint32_t addr, uint16_t N);
};


class ResponseFrame_MC_3E_BINARY
{
public:
    ResponseFrame_MC_3E_BINARY(QByteArray frame);
    bool parser(QByteArray frame);
    bool checkLegal();
    uint16_t dataLength();
    uint16_t errorCode();
    QByteArray responseData();
    QByteArray errorData();
protected:
    QByteArray m_data;
};

QString errorCodeString(uint16_t);

class ErrorData_MC_3E_BINARY
{
    /**
     * @brief parser 用来接收 ResponseFrame_MC_3E_BINARY 的 errorData()
     * @param data ResponseFrame_MC_3E_BINARY 的 errorData()
     * @return
     */
    bool parser(QByteArray data);
    QByteArray netNumber();
    QByteArray PLCNumber();
    QByteArray IONumber();
    QByteArray command();
    QByteArray subCommand();
protected:
    QByteArray m_data;
};



class Melsec_3E
{
public:
    Melsec_3E();
};

#endif // MELSEC_3E_BINARY_H
